var DataUtils = function () {

  return {
    set: function (key, value) {
      if (value == null) {
        sessionStorage.removeItem(key);
        return;
      }
      if (typeof value == "object") {
        value = JSON.stringify(value);
      }
      sessionStorage[key] = value;

    },
    get: function (key) {
      let value = sessionStorage[key] || null;
      if (/^\{(.*?)\}$/.test(value) || /^\[(.*?)\]$/.test(value)) {
        return JSON.parse(value);
      }
      return value;
    }
  }
}();
var ExcelUtils = function () {
  
  function s2ab(s) {
    if (typeof ArrayBuffer !== 'undefined') {
      var buf = new ArrayBuffer(s.length);
      var view = new Uint8Array(buf);
      for (var i = 0; i != s.length; ++i)
        view[i] = s.charCodeAt(i) & 0xFF;
      return buf;
    } else {
      var buf = new Array(s.length);
      for (var i = 0; i != s.length; ++i) buf[i] = s.charCodeAt(i) & 0xFF;
      return buf;
    }
  }
  function createExcel(wb, fileName) {
    
    let wopts = {bookType: 'xlsx', bookSST: false, type: 'binary'};//这里的数据是用来定义导出的格式类型
    var data = new File([s2ab(XLSX.write(wb, wopts))]
      , fileName, {type: 'text/plain;charset=utf-8'});
    upload("/upload", {"name": data.name, data}, (r) => {
      layer.msg("成功下载，路径：" + r["data"])
    }, (r) => {
      layer.msg("下载失败")
    })
  }

  function setItem(excelData){
    console.info("start",(new Date()).Format("yyyy-MM-dd hh:mm:ss.S"));
    let result = "";
    excelData = JSON.stringify(excelData);
    $.ajax({
      url: "/excel/data/upload",
      type: "POST",
      cache: false,
      async: false,
      data: excelData,
      success: r => {
        result = r;
        console.info("end",(new Date()).Format("yyyy-MM-dd hh:mm:ss.S"));
      },error: r=>{
        result = "error";
        console.error(r)
      }
    })
    return result;
  }
  function getItem(){
    let result = {};
    $.ajax({
      type: "post",
      url: `/excel/data`,
      cache: false,
      async: false,
      success: (r) => {
       result = r;
      }
    });
    return result;
  }
  return {
    createExcel,setItem,getItem
  }
}();
function getUrlParam(paraName) {
  var url = document.location.toString();
  var arrObj = url.split("?");

  if (arrObj.length > 1) {
    var arrPara = arrObj[1].split("&");
    var arr;

    for (var i = 0; i < arrPara.length; i++) {
      arr = arrPara[i].split("=");

      if (arr != null && arr[0] == paraName) {
        return arr[1];
      }
    }
    return "";
  } else {
    return "";
  }
}

function getExcelData(file, callBack) {
  var reader = new FileReader();
  reader.onload = function (e) {
    var data = e.target.result;
    var wb = XLSX.read(data, {type: 'binary'});
    var objData = JSON.parse(JSON.stringify(XLSX.utils.sheet_to_json(wb.Sheets[wb.SheetNames[0]])));
    callBack(objData);
  }
  reader.readAsBinaryString(file);
}

function getImageBase64(file, callBack) {
  var reader = new FileReader();
  reader.onload = function (e) {
    var data = e.target.result;
    callBack(data);
  }
  reader.readAsDataURL(file);
}

var pdf_fonts = {};
var fontsApi = {
  "addFileToVFS": function (name, content) {
    pdf_fonts[name] = content;
  }
}
Array.prototype.sortByNumKeys=function (keys=[]){
  if (typeof keys == "string") {
    keys = [keys];
  }
  let list = this;
  let compareFun=(a,b,i)=>{
    let [key, sortType] = keys[i].split(" ");
    sortType = sortType || "asc";
    if (sortType!="asc"){
      let c=a;
      a=b;
      b=c;
    }
    let r=0;
    let a1 = a[key] == "NULL" ? 0 : a[key];
    let b1 = b[key] == "NULL" ? 0 : b[key];
    if (isNaN(a1) || isNaN(b1)) {
      r= (a1 + "").localeCompare(b1 + "")
    } else {
      r= toNumber(a1) - toNumber(b1);
    }
    if (r==0 && i < keys.length-1){
      return compareFun(a,b,i+1);
    }
    return r;
  }
  return list.sort((a,b)=>compareFun(a,b,0));
}
Array.prototype.sortBy = function (keys = []) {
  if (typeof keys == "string") {
    keys = [keys];
  }
  let list = this;
  for (let i = keys.length - 1; i >= 0; i--) {

    let [key, a] = keys[i].split(" ");
    a = a || "asc";

    let sortFunc = {
      "asc": (a, b) => {
        let a1 = a[key] == "NULL" ? 0 : a[key];
        let b1 = b[key] == "NULL" ? 0 : b[key];
        if (isNaN(a1) || isNaN(b1)) {
          return (a1 + "").localeCompare(b1 + "")
        } else {
          return toNumber(a1) - toNumber(b1);
        }
      }, "desc": (a, b) => {
        return sortFunc["asc"](b, a);
      }
    };
    list = list.sort(sortFunc[a]);
  }
  return list;
}
Array.prototype.sortBy2 = function (keys, desc) {
  let strF = keys.map(i => "{" + i + "}").join("-");
  let getKey = (item) => {
  }
  let temp = [];
  $.each(this, (i, v) => {
    temp.push({"k": strF.format(v) + "", "v": v});
  });
  let sortFunc = (a, b) => {
    return a["k"].localeCompare(b["k"])
  }
  if (desc) {
    sortFunc = (a, b) => {
      return b["k"].localeCompare(a["k"])
    }
  }
  temp = temp.sort(sortFunc);
  return temp.map(item => item["v"])
}
Array.prototype.sortByLimit = function(keys = [], limit=1,cb){
  let list = this.sortBy(keys);
  let result = [];
  for(let i=0; i< list.length && i < limit;i++){
    let r = list[i];
    if (cb){r = cb(list[i],i);}
    result.push(r || list[i]);
  }
  return result;
};

/**
 * 排序并取前limit名次的数据,可以同分数
 * @param keys
 * @param limit
 * @param cb
 * @returns {[]}
 */
Array.prototype.sortByRank = function(keys = [],scoreName, maxRank=1, minRank=0,func){
  let preScore = null;
  let resultList = [];

  let list = this.sortBy(keys);
  for (let i = 0, rank = minRank; i < list.length; i++) {
    if (list[i] == null) {
      continue;
    }
    let curScore = toNumber(list[i][scoreName]);
    if (!curScore || curScore <= 0) {
      continue;
    }
    if (preScore == null || curScore != preScore) {
      rank++;
      if (rank > maxRank) {
        break;
      }
    }
    preScore = curScore;
    let item = list[i];
    if(func){
      item = func(item,rank);
    }
    resultList.push(item);
  }
  return resultList;
};

Array.prototype.groupBy = function (keys, func) {
  let result = [];
  let getKey = (key, item) => {
    return item[key];
  }
  keys = Array.isArray(keys) ? keys : [keys];
  // key = key.reduce((a,b)=>{return a+"&"+item[b]});
  let getKeyItem = (item) => keys.reduce((r, i) => {
    r[i] = item[i];
    return r;
  }, {});
  let groupFunc = (list, item, func) => {
    let kvi = getKeyItem(item);
    let key = Object.values(kvi).join("&");
    let temp = list[key];
    if (!temp) {
      temp = {"items": [], "key": kvi};
      list[key] = temp;
    }
    let newItem = item;
    if (func){
      let funItem = func(newItem, temp);
      if (funItem){
        newItem = funItem;
      }
    }
    temp["items"].push(newItem);
  }
  this.forEach(item => {
    groupFunc(result, item, func);
  });
  return Object.values(result);
}
Array.prototype.groupByNum = function (num, func) {
  let result = [];
  let group = [];
  let index = 0;
  let len = this.length - 1;
  func = func || ((item) => item);
  $.each(this, (ii, vv) => {
    index++;
    group.push(func(vv));
    if (index >= num || ii == len) {
      result.push(group);
      group = [];
      index = 0;
    }
  });
  return result;
};
Array.prototype.groupByNums = function (nums, func) {
  let result = [];
  let group = [];
  let index = 0;
  let len = this.length - 1;
  func = func || ((item) => item);
  let num = nums.shift();
  $.each(this, (ii, vv) => {
    index++;
    group.push(func(vv));

    if (index >= num || ii == len) {
      result.push(group);
      group = [];
      num = nums.shift();
      index = 0;
    }
    if (!num) {
      return false;
    }
  });
  return result;
}
Array.prototype.select = function (name) {
  let result = [];
  $.each(this, (ii, vv) => {
    let temp = vv[name];
    if (!temp) {
      return;
    }
    if (!result.includes(temp)) {
      result.push(temp);
    }
  });
  return result;
}

Array.prototype.toArray = function (){
  let list = this;
  let excelData = [];
  (list||[]).forEach(item => {
    let newItem = [];
    $.each(item, (k, v) => newItem.push(v))
    excelData.push(newItem);
  });
  return excelData;
}
function pushList(list, item, key, func) {
  let temp = list[key];
  if (!temp) {
    temp = {
      "items": []
    };
    list[key] = temp;
  }
  let newItem = $.extend({}, item);
  temp["items"].push(newItem);
  func && func(newItem);
}

String.prototype.addLine = function (str) {
  return this + "\r\n" + str;
}
String.prototype.format = function (args) {
  var result = this;
  if (arguments.length > 0) {
    if (arguments.length == 1 && typeof (args) == "object") {
      for (var key in args) {
        if (args[key] != undefined) {
          var reg = new RegExp("({" + key + "})", "g");
          result = result.replace(reg, args[key]);
        }
      }
    } else {
      for (var i = 0; i < arguments.length; i++) {
        if (arguments[i] != undefined) {
          //var reg = new RegExp("({[" + i + "]})", "g");//这个在索引大于9时会有问题，谢谢何以笙箫的指出
          var reg = new RegExp("({)" + i + "(})", "g");
          result = result.replace(reg, arguments[i]);
        }
      }
    }
  }
  return result;
}

$.fn.showJson = function (data) {
  let tempData = [];
  $.each(data, (i, v) => {
    if (Array.isArray(v)) {
      $.each(v, (ii, vv) => {
        tempData.push(vv);
      })
    } else {
      tempData.push(v);
    }
  });
  let $tbody = $(this).find("tbody");
  let $thead = $(this).find("thead");
  $tbody.empty();
  $thead.empty();
  columns = [];
  $.each(tempData, (i, v) => {
    if (columns.length == 0) {
      let $tr = $("<tr></tr>");
      $.each(v, (ii, vv) => {
        $tr.append("<th>" + ii + "</th>");
        columns.push(ii);
      });
      $thead.append($tr);
    }

    let $tr = $("<tr></tr>");
    $.each(columns, (ii, columnName) => {
      $tr.append("<td>" + v[columnName] + "</td>");
    })
    $tbody.append($tr);
  })
  //$(this).grid();
}
$.fn.grid = function () {
  let $this = $(this);

  let $grid = $this.data("is-grid");
  if (!$grid) {
    $grid = $('"<div class="grid"><div class="g-head"></div><div class="g-table"></div></div>');
    $this.data("is-grid", $grid);
    $this.before($grid);
    $grid.height($this.parent().height());
    $grid.width($this.parent().width());
    $grid.find(".g-table").append($this);
  }


  $gHead = $grid.find(".g-head");
  $gTable = $grid.find(".g-table");
  $gHead.empty();
  let $head = $this.find("thead");
  if ($head.length > 0) {
    let $gHeadTable = $("<table class='gridtable'></table>");
    $head.find("td,th").each((i, v) => {
      $(v).width($(v).width());
    })
    $gHeadTable.append($head[0].outerHTML);
    $gHead.append($gHeadTable);
    $gHead.show();


  } else {
    $gHead.hide();
  }

  //  $gTable.height($grid.height()-$gHead.height());
  $gTable.scrollTop(1);
  if ($gTable.scrollTop() > 0) {
    $gHead.css("right", "17px");
    $gTable.scrollTop(0);
  }
}

function toMap(list,col="id"){
  let result = {};
  (list||[]).forEach(item=>{
    result[item[col]]= item;
  })
  return result;
}
function toNumber(v) {
  if (typeof v === 'number'){
    return v;
  }
  let r = Number.parseFloat(v);
  if (Number.isNaN(r)) {
    return 0;
  } else {
    return r;
  }
}

function jsonToString(jsonItem){
  let r = [];
  for (let k in jsonItem) {
    r.push(`${k}=${jsonItem[k]}`)
  }
  return r.join(",");
}
function round(num, decimal) {
  if (isNaN(num)) {
    return 0;
  }
  const p1 = Math.pow(10, decimal + 1);
  const p2 = Math.pow(10, decimal);
  return Math.round(num * p1 / 10) / p2;
}

function toRoundFixed(num, decimal=2) {
  return round(num, decimal).toFixed(decimal);
}

function addPreZero(list, num = 3) {
  let attachZero = (v, num) => ('000000000' + v).slice(-num);
  (list || []).forEach(v => {
    if (v["TeamNumber"] && (v["TeamNumber"]+"").length <=3) {
      v["TeamNumber"] = attachZero(v["TeamNumber"], 3);
    }
    if (v["StudentNumber"]&& (v["TeamNumber"]+"").length <=6) {
      v["StudentNumber"] = attachZero(v["StudentNumber"], 6);
    }
  });
}

function isRealNum(val) {
  // isNaN()函数 把空串 空格 以及NUll 按照0来处理 所以先去除，

  if (val === "" || val == null) {
    return false;
  }
  if (!isNaN(val)) {
    //对于空数组和只有一个数值成员的数组或全是数字组成的字符串，isNaN返回false，例如：'123'、[]、[2]、['123'],isNaN返回false,
    //所以如果不需要val包含这些特殊情况，则这个判断改写为if(!isNaN(val) && typeof val === 'number' )
    return true;
  } else {
    return false;
  }
}

function val(v) {
  if (typeof v == "string") {
    if (/^{.*}$/.test(v) || /^\[.*\]$/.test(v)) {
      try {
        return JSON.parse(v)
      } catch (e) {
      }
    }
  }

  return v;
}

// ew Date()).Format("yyyy-MM-dd hh:mm:ss.S") ==> 2006-07-02 08:09:04.423
// (new Date()).Format("yyyy-M-d h:m:s.S")      ==> 2006-7-2 8:9:4.18
Date.prototype.Format = function (fmt) {
  var o = {
    "M+": this.getMonth() + 1,                 //月份
    "d+": this.getDate(),                    //日
    "h+": this.getHours(),                   //小时
    "m+": this.getMinutes(),                 //分
    "s+": this.getSeconds(),                 //秒
    "q+": Math.floor((this.getMonth() + 3) / 3), //季度
    "S": this.getMilliseconds()             //毫秒
  };
  if (/(y+)/.test(fmt))
    fmt = fmt.replace(RegExp.$1, (this.getFullYear() + "").substr(4 - RegExp.$1.length));
  for (var k in o)
    if (new RegExp("(" + k + ")").test(fmt))
      fmt = fmt.replace(RegExp.$1, (RegExp.$1.length == 1) ? (o[k]) : (("00" + o[k]).substr(("" + o[k]).length)));
  return fmt;
}

// if(jsPDF){
//  // jsPDF.prototype.text2(text,)
// }

function upload(url, data, cb) {

  var formData = new FormData();
  $.each(data, (k, v) => {
    formData.append(k, v);
  })

  $.ajax({
    url: url,// "/upload",
    type: "POST",
    contentType: false,
    processData: false,
    data: formData,
    success: r => {
      cb && cb(r);
    }
  })
}

var $$ = {};
$$.listSync = (name, data, cb, orderBy) => {
  if (typeof data == "function") {
    cb = data;
    data = null;
  }
  if (orderBy) {
    data = data || {};
    data["_orderby"] = orderBy;
  }
  let result = null;
  $.ajax({
    type: "post",
    url: `/${name}/list`,
    cache: false,
    async: false,
    data,
    success: (r) => {
      if (r && r.status) {
        result = r.data;
        cb && cb(r.data || [])
      }
    }
  })
  return result;
}
$$.fetchSync = (name, id, cb) => {


  let result = null;
  let data = {"id": id};
  $.ajax({
    type: "post",
    url: `/${name}/fetch`,
    cache: false,
    async: false,
    data,
    success: (r) => {
      if (r && r.status) {
        result = r.data;
        cb && cb(r.data || [])
      }
    }
  })
  return result;
};
$$.listBy = (name, orderBy, data, cb) => {
  $$.list(name, data, cb, orderBy);
};
$$.list = (name, data, cb, orderBy) => {
  if (typeof data == "function") {
    cb = data;
    data = null;
  }
  if (orderBy) {
    data = data || {};
    data["_orderby"] = orderBy;
  }
  $.post(`/${name}/list`, data, (r) => {
    if (r && r.status) {
      cb && cb(r.data || [])
    }
  })
}
$$.fetch = (name, id, cb) => {
  $.post(`/${name}/fetch`, {"id": id}, (r) => {
    if (r && r.status) {
      cb && cb(r.data || {})
    }
  })
};
$$.delete = (name, id, cb) => {
  $.post(`/${name}/delete`, {"id": id}, (r) => {
    if (r && r.status) {
      cb(r.data || {})
    }
  })
};
$$.op = (name, op, data, cb, err_cb = null) => {
  let data2 = data;
  if (typeof (data) == "object") {
    data2 = JSON.stringify(data)
  }
  $.ajax({
    "type": "POST",
    url: `/${name}/${op}`,
    contentType: "application/json",
    dataType: "json",
    data: data2,
    success: (r) => {
      if (r && r.status) {
        cb && cb(r.data || {})
      } else {
        err_cb && err_cb(r)
      }
    },
    error: err_cb
  });
}
$$.save = (name, data, cb, err_cb = null) => {
  let data2 = data;
  if (typeof (data) == "object") {
    data2 = JSON.stringify(data)
  }
  $.ajax({
    "type": "POST",
    url: `/${name}/save`,
    contentType: "application/json",
    dataType: "json",
    data: data2,
    success: (r) => {
      if (r && r.status) {
        cb && cb(r.data || {})
      } else {
        err_cb && err_cb(r)
      }
    },
    error: err_cb
  });
};
$$.upload = (name, data, cb) => {
  upload(`/${name}/upload`, data, (r) => {
    if (r && r.status) {
      cb && cb(r.data || [])
    }
  });
};
$$.uuid = (cb) => {
  $.post("/uuid", (r) => {
    if (r && r.status) {
      cb && cb(r.data);
    }
  })
}
